import 'dart:io';

import 'package:async/async.dart';
import 'package:dk_flutter_base/dk_core.dart';
import 'package:dk_flutter_base/dk_ui.dart';
import 'package:dk_flutter_module_sale/common/plugin/plugin_common.dart';
import 'package:flutter/services.dart';
import 'package:flutter_cache_manager/flutter_cache_manager.dart';

enum DKImageType { asset, file, network }

class DkImage {
  final DKImageType imageType;
  final String path;
  final Key key;
  final double width;
  final double height;
  final Color color;
  final BoxFit fit;
  final AlignmentGeometry alignment;
  final ImageRepeat repeat;
  final bool matchTextDirection;
  final BlendMode colorBlendMode;
  final FilterQuality filterQuality;

//----------------------------Image widget----------------------------
  final ImageFrameBuilder frameBuilder;
  final String semanticLabel;
  final bool excludeFromSemantics;
  final double scale;
  final Rect centerSlice;
  final bool gaplessPlayback;

  //---------Image.asset---------
  final String package;
  final AssetBundle bundle;

//----------------------------CachedNetworkImage widget----------------------------
  final BaseCacheManager cacheManager;
  final ImageWidgetBuilder imageBuilder;
  final PlaceholderWidgetBuilder placeholder;
  final LoadingErrorWidgetBuilder errorWidget;
  final Duration placeholderFadeInDuration;
  final Duration fadeOutDuration;
  final Curve fadeOutCurve;
  final Duration fadeInDuration;
  final Curve fadeInCurve;
  final Map<String, String> httpHeaders;
  final bool useOldImageOnUrlChange;

  DkImage({
    this.imageType,
    @required this.path,
    this.key,
    this.width,
    this.height,
    this.fit,
    this.alignment,
    this.repeat,
    this.color,
    this.matchTextDirection,
    this.colorBlendMode,
    this.filterQuality,
    //----------------------
    this.imageBuilder,
    this.placeholder,
    this.errorWidget,
    this.fadeOutDuration,
    this.fadeOutCurve,
    this.fadeInDuration,
    this.fadeInCurve,
    this.httpHeaders,
    this.cacheManager,
    this.useOldImageOnUrlChange,
    this.placeholderFadeInDuration,
    //----------------------
    this.frameBuilder,
    this.semanticLabel,
    this.excludeFromSemantics,
    this.scale,
    this.centerSlice,
    this.gaplessPlayback,
    //----------------------
    this.package,
    this.bundle,
  });

  DkImage.asset(
      {@required this.path,
      this.key,
      this.bundle,
      this.frameBuilder,
      this.semanticLabel,
      this.excludeFromSemantics = false,
      this.scale,
      this.width,
      this.height,
      this.color,
      this.colorBlendMode,
      this.fit,
      this.alignment = Alignment.center,
      this.repeat = ImageRepeat.noRepeat,
      this.centerSlice,
      this.matchTextDirection = false,
      this.gaplessPlayback = false,
      this.package,
      this.filterQuality = FilterQuality.low})
      : imageType = DKImageType.asset,
        cacheManager = null,
        imageBuilder = null,
        placeholder = null,
        errorWidget = null,
        placeholderFadeInDuration = null,
        fadeOutDuration = null,
        fadeOutCurve = null,
        fadeInDuration = null,
        fadeInCurve = null,
        httpHeaders = null,
        useOldImageOnUrlChange = null;

  DkImage.file(
      {@required this.path,
      this.key,
      this.frameBuilder,
      this.semanticLabel,
      this.excludeFromSemantics = false,
      this.scale = 1.0,
      this.width,
      this.height,
      this.color,
      this.colorBlendMode,
      this.fit = BoxFit.fill,
      this.alignment = Alignment.center,
      this.repeat = ImageRepeat.noRepeat,
      this.centerSlice,
      this.matchTextDirection = false,
      this.gaplessPlayback = false,
      this.filterQuality = FilterQuality.low})
      : imageType = DKImageType.asset,
        cacheManager = null,
        package = null,
        bundle = null,
        imageBuilder = null,
        placeholder = null,
        errorWidget = null,
        placeholderFadeInDuration = null,
        fadeOutDuration = null,
        fadeOutCurve = null,
        fadeInDuration = null,
        fadeInCurve = null,
        httpHeaders = null,
        useOldImageOnUrlChange = null;

  DkImage.network(
      {@required this.path,
      this.key,
      this.imageBuilder,
      this.placeholder,
      this.errorWidget,
      this.fadeOutDuration: const Duration(milliseconds: 1000),
      this.fadeOutCurve: Curves.easeOut,
      this.fadeInDuration: const Duration(milliseconds: 500),
      this.fadeInCurve: Curves.easeIn,
      this.width,
      this.height,
      this.fit = BoxFit.fill,
      this.alignment: Alignment.center,
      this.repeat: ImageRepeat.noRepeat,
      this.matchTextDirection: false,
      this.httpHeaders,
      this.cacheManager,
      this.useOldImageOnUrlChange: false,
      this.color,
      this.filterQuality: FilterQuality.low,
      this.colorBlendMode,
      this.placeholderFadeInDuration})
      : imageType = DKImageType.network,
        package = null,
        bundle = null,
        frameBuilder = null,
        semanticLabel = null,
        excludeFromSemantics = null,
        scale = null,
        centerSlice = null,
        gaplessPlayback = null;

  Widget build() {
    DKImageType imageTypeFinal;
    if (null == imageType) {
      if (path.startsWith("http")) {
        imageTypeFinal = DKImageType.network;
      } else if (path.startsWith("images/")) {
        imageTypeFinal = DKImageType.asset;
      } else {
        imageTypeFinal = DKImageType.file;
      }
    } else {
      imageTypeFinal = imageType;
    }
    Widget result;
    switch (imageTypeFinal) {
      case DKImageType.asset:
        result = Image.asset(
          path,
          key: key,
          bundle: bundle,
          frameBuilder: frameBuilder,
          semanticLabel: semanticLabel,
          excludeFromSemantics: excludeFromSemantics ?? false,
          scale: scale,
          width: width,
          height: height,
          color: color,
          colorBlendMode: colorBlendMode,
          fit: fit ?? BoxFit.fill,
          alignment: alignment ?? Alignment.center,
          repeat: repeat ?? ImageRepeat.noRepeat,
          centerSlice: centerSlice,
          matchTextDirection: matchTextDirection ?? false,
          gaplessPlayback: gaplessPlayback ?? false,
          package: package,
          filterQuality: filterQuality ?? FilterQuality.low,
        );
        break;
      case DKImageType.file:
        result = Platform.isIOS
            ? FutureBuilderImage(
                key: key,
                path: path,
                scale: scale ?? 1.0,
                frameBuilder: frameBuilder,
                semanticLabel: semanticLabel,
                excludeFromSemantics: excludeFromSemantics ?? false,
                width: width,
                height: height,
                color: color,
                colorBlendMode: colorBlendMode,
                fit: fit ?? BoxFit.fill,
                alignment: alignment ?? Alignment.center,
                repeat: repeat ?? ImageRepeat.noRepeat,
                centerSlice: centerSlice,
                matchTextDirection: matchTextDirection ?? false,
                gaplessPlayback: gaplessPlayback ?? false,
                filterQuality: filterQuality ?? FilterQuality.low,
              )
            : Image(
                image: FileImageEx(File(path), scale: scale ?? 1.0),
                key: key,
                frameBuilder: frameBuilder,
                semanticLabel: semanticLabel,
                excludeFromSemantics: excludeFromSemantics ?? false,
                width: width,
                height: height,
                color: color,
                colorBlendMode: colorBlendMode,
                fit: fit ?? BoxFit.fill,
                alignment: alignment ?? Alignment.center,
                repeat: repeat ?? ImageRepeat.noRepeat,
                centerSlice: centerSlice,
                matchTextDirection: matchTextDirection ?? false,
                gaplessPlayback: gaplessPlayback ?? false,
                filterQuality: filterQuality ?? FilterQuality.low,
              );
        break;
      case DKImageType.network:
        result = CachedNetworkImage(
          imageUrl: path,
          imageBuilder: imageBuilder,
          placeholder: placeholder,
          errorWidget: errorWidget,
          fadeOutDuration:
              fadeOutDuration ?? const Duration(milliseconds: 1000),
          fadeOutCurve: fadeOutCurve ?? Curves.easeOut,
          fadeInDuration: fadeInDuration ?? const Duration(milliseconds: 500),
          fadeInCurve: fadeInCurve ?? Curves.easeIn,
          width: width,
          height: height,
          fit: fit ?? BoxFit.fill,
          alignment: alignment ?? Alignment.center,
          repeat: repeat ?? ImageRepeat.noRepeat,
          matchTextDirection: matchTextDirection ?? false,
          httpHeaders: httpHeaders,
          cacheManager: cacheManager,
          useOldImageOnUrlChange: useOldImageOnUrlChange ?? false,
          color: color,
          filterQuality: filterQuality ?? FilterQuality.low,
          colorBlendMode: colorBlendMode,
          placeholderFadeInDuration: placeholderFadeInDuration,
        );
        break;
      default:
        result = Container();
    }
    return result;
  }
}

class FutureBuilderImage extends StatefulWidget {
  final String path;
  final Key key;
  final double width;
  final double height;
  final Color color;
  final BoxFit fit;
  final AlignmentGeometry alignment;
  final ImageRepeat repeat;
  final bool matchTextDirection;
  final BlendMode colorBlendMode;
  final FilterQuality filterQuality;

  final ImageFrameBuilder frameBuilder;
  final String semanticLabel;
  final bool excludeFromSemantics;
  final double scale;
  final Rect centerSlice;
  final bool gaplessPlayback;

  FutureBuilderImage({
    this.path,
    this.key,
    this.width,
    this.height,
    this.color,
    this.fit,
    this.alignment,
    this.repeat,
    this.matchTextDirection,
    this.colorBlendMode,
    this.filterQuality,
    this.frameBuilder,
    this.semanticLabel,
    this.excludeFromSemantics,
    this.scale,
    this.centerSlice,
    this.gaplessPlayback,
  });

  @override
  State<FutureBuilderImage> createState() {
    return FutureBuilderImageState();
  }
}

class FutureBuilderImageState extends State<FutureBuilderImage> {
  AsyncMemoizer<String> _memoizer;

  @override
  void initState() {
    super.initState();
    _memoizer = AsyncMemoizer<String>();
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<String>(future: _memoizer.runOnce(() async {
      return await CommonPlugin().getIosPath();
    }), builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
      switch (snapshot.connectionState) {
        case ConnectionState.none:
        case ConnectionState.active:
        case ConnectionState.waiting:
          return Center(
            child: CircularProgressIndicator(),
          );
        case ConnectionState.done:
          if (snapshot.hasError) return Container();
          String pathFinal = widget.path.contains(snapshot.data)
              ? widget.path
              : snapshot.data + widget.path;

          return Image(
            image: FileImageEx(File(pathFinal), scale: widget.scale ?? 1.0),
            key: widget.key,
            frameBuilder: widget.frameBuilder,
            semanticLabel: widget.semanticLabel,
            excludeFromSemantics: widget.excludeFromSemantics ?? false,
            width: widget.width,
            height: widget.height,
            color: widget.color,
            colorBlendMode: widget.colorBlendMode,
            fit: widget.fit ?? BoxFit.fill,
            alignment: widget.alignment ?? Alignment.center,
            repeat: widget.repeat ?? ImageRepeat.noRepeat,
            centerSlice: widget.centerSlice,
            matchTextDirection: widget.matchTextDirection ?? false,
            gaplessPlayback: widget.gaplessPlayback ?? false,
            filterQuality: widget.filterQuality ?? FilterQuality.low,
          );
        default:
          return Container();
      }
    });
  }
}

class FileImageEx extends FileImage {
  int fileSize;

  FileImageEx(File file, {double scale = 1.0})
      : assert(file != null),
        assert(scale != null),
        super(file, scale: scale) {
    fileSize = file.lengthSync();
  }

  @override
  bool operator ==(dynamic other) {
    if (other.runtimeType != runtimeType) return false;
    final FileImageEx typedOther = other;
    return file?.path == typedOther.file?.path &&
        scale == typedOther.scale &&
        fileSize == typedOther.fileSize;
  }

  @override
  int get hashCode => hashValues(file?.path, scale, fileSize);
}
